#ifndef __IM_TEXT_H__
#define __IM_TEXT_H__

#include <im_base_types.h>
#include <im_object.h>
#include <im_attributes.h>

/**
 * @defgroup IMText
 * @ingroup PublicIME
 * @{
 */

/** @struct IMText
 *  @brief IMText class is used to manipulate a piece of multilingual
 *         text along with its text attributes.
 *
 * UCS-4 encoding is used internally. Each single UCS-4 code will be
 * treated as one character. Characters which are composed by multiple
 * UCS-4 codes will not be interpreted, such as code sequence to represent
 * a standard variation and unicode named character sequences.
 */

IM_BEGIN_DECLS

#define IM_TEXT(p)                  (IM_TYPE_INSTANCE_CHECK_CAST((p),IM_TYPE_TEXT,IMText))
#define IM_CONST_TEXT(p)            (IM_TYPE_INSTANCE_CHECK_CAST_CONST((p),IM_TYPE_TEXT,IMText))
#define IM_TEXT_CLASS(c)            (IM_TYPE_CLASS_CHECK_CAST((c),IM_TYPE_TEXT,IMTextClass))
#define IM_IS_TEXT(p)               (IM_TYPE_INSTANCE_CHECK_TYPE((p),IM_TYPE_TEXT))
#define IM_IS_TEXT_CLASS(c)         (IM_TYPE_CLASS_CHECK_TYPE((c),IM_TYPE_TEXT))
#define IM_TEXT_GET_CLASS(p)        (IM_TYPE_INSTANCE_GET_CLASS_CAST((p),IM_TYPE_TEXT,IMTextClass))

typedef struct _IMText         IMText;
typedef struct _IMTextClass    IMTextClass;

/**
 * @brief Create a new empty IMText object.
 * @return a pointer to a newly created IMText object.
 */
IMText*         im_text_new                     ();

/**
 * @brief Create a new IMText object from an UTF-8 string.
 *
 * @param str an UTF-8 string.
 * @param len Length of str, -1 means until 0.
 * @return the newly created IMText object.
 */
IMText*         im_text_new_from_utf8_string    (const IMChar       *str,
                                                 IMInt               len);

/**
 * @brief Create a new IMText object from arbitrary printf result.
 *
 * The result string must be UTF-8 encoded.
 *
 * @param format format string.
 * @param ... arbitrary variables to be printed according to format string.
 * @return the newly created IMText object.
 */
IMText*         im_text_new_from_utf8_printf    (const IMChar       *format,
                                                 ...) IM_GNUC_PRINTF(1,2);

/**
 * @brief Create a new IMText object from an UTF-16 string.
 *
 * Byte order of the UTF-16 string must be same as the machine
 * endian. And this function won't recognize BOM.
 *
 * @param str an UTF-16 string.
 * @param len Length of str, -1 means until 0.
 * @return the newly created IMText object.
 */
IMText*         im_text_new_from_utf16_string   (const IMUInt16     *str,
                                                 IMInt               len);
/**
 * @brief Create a new IMText object from an UCS-4 string.
 *
 * Byte order of the UCS-4 string must be same as the machine
 * endian. And this function won't recognize BOM.
 *
 * @param str an UCS-4 string.
 * @param len Length of str, -1 means until 0.
 * @return the newly created IMText object.
 */
IMText*         im_text_new_from_ucs4_string    (const IMUniChar    *str,
                                                 IMInt               len);
/**
 * @brief Erases the content of a IMText object, making it empty.
 *
 * All content will be removed.
 *
 * @param text a pointer to an IMText object.
 */
void            im_text_clear                   (IMText             *text);

/**
 * @brief Preallocate enough memory for specified number of characters
 *        to prevent reallocation when inserting many characters.
 *
 * @param text a pointer to an IMText object.
 * @param size number of characters required.
 */
void            im_text_reserve                 (IMText             *text,
                                                 IMSize              size);
/**
 * @brief Returns the total number of characters that
 *        the IMText can hold before needing to allocate
 *        more memory.
 *
 * @param text a pointer to an IMText object.
 */
IMSize          im_text_capacity                 (const IMText       *text);
/**
 * @brief Returns true if the IMText object is empty.
 *
 * @param text a pointer to an IMText object.
 */
IMBool          im_text_empty                    (const IMText       *text);

/**
 * @brief Resizes the IMText object to the specified number of characters.
 *
 * This function will resize the IMText object to the specified number
 * of characters. If the number is smaller than the IMText's current size
 * the IMText is truncated, otherwise the IMText is extended and new
 * elements are set to fill_ch.
 *
 * @param text a pointer to an IMText object to be resized.
 * @param new_size number of characters the IMText should contain.
 * @param fill_ch character to fill any new elements.
 */
void            im_text_resize                  (IMText             *text,
                                                 IMSize              new_size,
                                                 IMUniChar           fill_ch);
/**
 * @brief Load IMText content from an UTF-8 string.
 *
 * Old content and attributes will be lost.
 *
 * @param text a pointer to an IMText object.
 * @param str an UTF-8 string.
 * @param len Length of str, -1 means until 0.
 * @return the original IMText object on success, 0 if failed.
 */
IMText*         im_text_from_utf8_string        (IMText             *text,
                                                 const IMChar       *str,
                                                 IMInt               len);
/**
 * @brief Load IMText content from an UTF-16 string.
 *
 * Byte order of the UTF-16 string must be same as the machine
 * endian. And this function won't recognize BOM.
 * Old content and attributes will be lost.
 *
 * @param text a pointer to an IMText object
 * @param str a pointer to a buffer that cantants an UTF-16 string.
 * @param len Length of str, -1 means until 0.
 * @return the original IMText object on success, 0 if failed.
 */
IMText*         im_text_from_utf16_string       (IMText             *text,
                                                 const IMUInt16     *str,
                                                 IMInt               len);
/**
 * @brief Load IMText content from an UCS-4 string.
 *
 * Byte order of the UCS-4 string must be same as the machine
 * endian. And this function won't recognize BOM.
 * Old content and attributes will be lost.
 *
 * @param text a pointer to an IMText object.
 * @param str an UCS-4 string.
 * @param len Length of str, -1 means until 0.
 * @return the original IMText object on success, 0 if failed.
 */
IMText*         im_text_from_ucs4_string        (IMText             *text,
                                                 const IMUniChar    *str,
                                                 IMInt               len);
/**
 * @brief Output the content of an IMText object to a buffer with UTF-8 encoding.
 *
 * @param text a pointer to an IMText object.
 * @param dest a buffer to hold result utf-8 string.
 * @param dest_size size of dest buffer.
 * @return How many bytes actually written into dest buffer.
 */
IMSize          im_text_to_utf8_string          (const IMText       *text,
                                                 IMChar             *dest,
                                                 IMSize              dest_size);
/**
 * @brief Output the content of an IMText object to a buffer with UTF-16 encoding.
 *
 * The result UTF-16 string has the same byte order than current machine endian.
 *
 * @param text a pointer to an IMText object.
 * @param dest a buffer to hold result utf-16 string.
 * @param dest_size size of dest buffer.
 * @return How many uint16 elements actually written into dest buffer.
 */
IMSize          im_text_to_utf16_string         (const IMText       *text,
                                                 IMUInt16           *dest,
                                                 IMSize              dest_size);
/**
 * @brief Output the content of an IMText object to a buffer with UCS-4 encoding.
 *
 * The result UCS-4 string has the same byte order than current machine endian.
 *
 * @param text a pointer to an IMText object
 * @param dest a buffer to hold result ucs4 string.
 * @param dest_size size of dest buffer.
 * @return How many IMUniChar elements actually written into dest buffer.
 */
IMSize          im_text_to_ucs4_string          (const IMText       *text,
                                                 IMUniChar          *dest,
                                                 IMSize              dest_size);
/**
 * @brief Return length of an IMText object, in number of characters.
 *
 * @param text a pointer to an IMText object
 * @return The lenght of the IMText object, in number of characters.
 */
IMSize          im_text_length                  (const IMText       *text);
/**
 * @brief Return how many bytes space required when converting an IMText object
 *        to an utf-8 string. Not including the ending zero.
 *
 * This function can be used to determine the minimum required buffer size
 * when using im_text_to_utf8_string() to convert an IMText object to an 
 * utf-8 string.
 *
 * @param text a pointer to an IMText object
 * @return How many bytes space required when converting an IMText object to an utf-8 string.
 */
IMSize          im_text_utf8_length             (const IMText       *text);
/**
 * @brief Return how many uint16 space required when converting an IMText object
 *        to an utf-16 string. Not including the ending zero.
 *
 * This function can be used to determine the minimum required buffer size
 * when using im_text_to_utf16_string() to convert an IMText object to an 
 * utf-16 string.
 *
 * @param text a pointer to an IMText object
 * @return How many bytes space required when converting an IMText object to an utf-16 string.
 */
IMSize          im_text_utf16_length            (const IMText       *text);
/**
 * @brief Get the character at specified index in an IMText object.
 *
 * @param text a pointer to an IMText object.
 * @param idx the character index, must less than text length.
 * @return the unicode character at the index,
 *         or IM_UNICHAR_INVALID if the index is invalid.
 */
IMUniChar       im_text_get_char                (const IMText       *text,
                                                 IMSize              idx);

/**
 * @brief Set the character at specified index in an IMText object to
 *        a given character.
 *
 * @param text a pointer to an IMText object.
 * @param idx the character index,
 *        must less than the length of this IMText object.
 * @param ch The character code to be set, if it's 0 then the text
 *           will be truncated.
 */
void            im_text_set_char                (IMText             *text,
                                                 IMSize              idx,
                                                 IMUniChar           ch);
/**
 * @brief Create a new IMText object containing a sub portion of a given
 *        IMText object.
 *
 * @param text a popinter to an IMText object.
 * @param pos start position of the sub portion.
 * @param len length of the sub portion.
 * @return a newly created IMText object containing the sub text. It must
 *         be released by im_object_unref() afterwards.
 */
IMText*         im_text_get_sub_text            (const IMText       *text,
                                                 IMSize              pos,
                                                 IMSize              len);
/**
 * @brief Prepend an IMText object into the beginning of a IMText object.
 *
 * @param text a pointer to an IMText object.
 * @param other a pointer to an IMText object which will be prepended into text.
 * @return a pointer to text.
 */
IMText*         im_text_prepend                 (IMText             *text,
                                                 const IMText       *other);
/**
 * @brief Prepend an utf-8 string into the beginning of a IMText object.
 *
 * @param text a pointer to an IMText object.
 * @param str a pointer to an buffer that contains a utf-8 string.
 * @param len the length of string.
 * @return a pointer to text.
 */
IMText*         im_text_prepend_utf8_string     (IMText             *text,
                                                 const IMChar       *str,
                                                 IMInt               len);
/**
 * @brief Prepend an utf-16 string into the beginning of a IMText object.
 *
 * @param text a pointer to an IMText object.
 * @param str a pointer to an buffer that contains a utf-16 string.
 * @param len the length of string.
 * @return a pointer to text.
 */
IMText*         im_text_prepend_utf16_string    (IMText             *text,
                                                 const IMUInt16     *str,
                                                 IMInt               len);
/**
 * @brief Prepend an unicode string string into the beginning of a IMText object.
 *
 * @param text a pointer to an IMText object.
 * @param str a pointer to an buffer that contains a unicode string.
 * @param len the length of string.
 * @return a pointer to text.
 */
IMText*         im_text_prepend_ucs4_string     (IMText             *text,
                                                 const IMUniChar    *str,
                                                 IMInt               len);

/**
 * @brief Prepend an unicode character into the beginning of a IMText object.
 *
 * @param text a pointer to an IMText object.
 * @param ch a character which will be prepended into text.
 * @return text.
 */
IMText*         im_text_prepend_unichar         (IMText             *text,
                                                 IMUniChar           ch);
/**
 * @brief Append an IMText object into the end of a IMText object.
 *
 * @param text a pointer to an IMText object.
 * @param other an IMText object which will be appended into text.
 * @return a pointer to text.
 */
IMText*         im_text_append                  (IMText             *text,
                                                 const IMText       *other);

/**
 * @brief Append an utf-8 string into the end of a IMText object.
 *
 * @param text a pointer to an IMText object.
 * @param str a pointer to an buffer that contains a utf-8 string.
 * @param len the length of string.
 * @return a pointer to text.
 */
IMText*         im_text_append_utf8_string      (IMText             *text,
                                                 const IMChar       *str,
                                                 IMInt               len);
/**
 * @brief Append an utf-16 string into the end of a IMText object.
 *
 * @param text a pointer to an IMText object.
 * @param str a pointer to an buffer that contains a utf-16 string.
 * @param len the length of string.
 * @return a pointer to text.
 */
IMText*         im_text_append_utf16_string     (IMText             *text,
                                                 const IMUInt16     *str,
                                                 IMInt               len);
/**
 * @brief Append an unicode string into the end of a IMText object.
 *
 * @param text a pointer to an IMText object.
 * @param str a pointer to an buffer that contains a unicode string.
 * @param len the length of string.
 * @return a pointer to text.
 */
IMText*         im_text_append_ucs4_string      (IMText             *text,
                                                 const IMUniChar    *str,
                                                 IMInt               len);
/**
 * @brief Append an unicode char into the end of a IMText object.
 *
 * @param text a pointer to an IMText object.
 * @param ch a unicode char
 * @return a pointer to text.
 */
IMText*         im_text_append_unichar          (IMText             *text,
                                                 IMUniChar           ch);
/**
 * @brief Insert an IMText object into an IMText object at the specified position.
 *
 * @param text a pointer to an IMText object.
 * @param pos position in text.
 * @param other an IMText object to be inserted into text.
 * @return text.
 */
IMText*         im_text_insert                  (IMText             *text,
                                                 IMSize              pos,
                                                 const IMText       *other);

/**
 * @brief Insert an utf-8 string into an IMText object at the specified position.
 *
 * @param text a pointer to an IMText object.
 * @param pos position in text.
 * @param str a pointer to a bufffer that cantains utf-8 string.
 * @param len the lenght of utf-8 string
 * @return a pointer to text.
 */
IMText*         im_text_insert_utf8_string      (IMText             *text,
                                                 IMSize              pos,
                                                 const IMChar       *str,
                                                 IMInt               len);
/**
 * @brief Insert an utf-16 string into an IMText object at the specified position.
 *
 * @param text a pointer to an IMText object.
 * @param pos position in text.
 * @param str a pointer to a bufffer that cantains utf-8 string.
 * @param len the lenght of utf-16 string
 * @return a pointer to text.
 */
IMText*         im_text_insert_utf16_string     (IMText             *text,
                                                 IMSize              pos,
                                                 const IMUInt16     *str,
                                                 IMInt               len);
/**
 * @brief Insert an unicode string into an IMText object at the specified position.
 *
 * @param text a pointer to an IMText object.
 * @param pos position in text.
 * @param str a pointer to a bufffer that cantains unicode string.
 * @param len the lenght of utf-16 string
 * @return a pointer to text.
 */
IMText*         im_text_insert_ucs4_string      (IMText             *text,
                                                 IMSize              pos,
                                                 const IMUniChar    *str,
                                                 IMInt               len);

/**
 * @brief Insert an unicode character into an IMText object at the specified position.
 *
 * @param text a pointer to an IMText object.
 * @param pos position in text.
 * @param ch an character to be inserted into text.
 * @return text.
 */
IMText*         im_text_insert_unichar          (IMText             *text,
                                                 IMSize              pos,
                                                 IMUniChar           ch);
/**
 * @brief Erase a specified portion of an IMText object.
 *
 * @param text a pointer to an IMText object.
 * @param pos position of the portion to be erased.
 * @param len length of the portion.
 * @return text
 */
IMText*         im_text_erase                   (IMText             *text,
                                                 IMSize              pos,
                                                 IMSize              len);
/**
 * @brief Add an attribute to a specified portion of an IMText object.
 *
 * Ownership of the attribute will be assumed by the IMText object.
 *
 * @param text a pointer to an IMText object.
 * @param pos position of the portion.
 * @param len length of the portion.
 * @param attr attribute to be added to the portion.
 */
void            im_text_add_attribute           (IMText             *text,
                                                 IMSize              pos,
                                                 IMSize              len,
                                                 IMAttribute        *attr);

/**
 * @brief Remove attributes that match a given type
 *        in a specified portion of an IMText object.
 *
 * @param text a pointer to an IMText object.
 * @param pos position of the portion.
 * @param len length of the portion.
 * @param attrtype attribute type to be removed.
 */
void            im_text_remove_attribute        (IMText             *text,
                                                 IMSize              pos,
                                                 IMSize              len,
                                                 IMType              attrtype);

/**
 * @brief Remove all attributes in a specified portion of an IMText object.
 *
 * @param text a pointer to an IMText object.
 * @param pos position of the portion.
 * @param len length of the portion.
 */
void            im_text_clear_attributes        (IMText             *text,
                                                 IMSize              pos,
                                                 IMSize              len);

/**
 * @brief Get all attributes in a specified portion of an IMText object.
 *
 * The range of returned attributes are relative to pos.
 *
 * @param text a pointer to an IMText object.
 * @param pos position of the portion.
 * @param len length of the portion.
 * @return a newly created IMAttrList object containing the attributes.
 *         It must be released by im_object_unref() afterwards.
 */
IMAttrList*     im_text_get_attributes          (const IMText       *text,
                                                 IMSize              pos,
                                                 IMSize              len);
/**
 * @brief Set an IMAttrList object to an IMText object.
 *
 * Old list will be released. Ownership of of the new list will be
 * assumed by the IMText object.
 *
 * @param text the IMText object.
 * @param attrs the IMAttrList object.
 */
void            im_text_set_attr_list           (IMText             *text,
                                                 IMAttrList         *attrs);
/**
 * @brief Get the IMAttrList object used by an IMText object.
 *
 * @param text a pointer to an IMText object.
 *
 * @return the IMAttrList object currently used by text. It shouldn't
 *         be changed or released by caller.
 */
IMAttrList*     im_text_get_attr_list           (const IMText       *text);

/**
 * @brief Duplicate the IMAttrList object used by an IMText object.
 *
 * @param text a pointer to an IMText object.
 * @return a copy of the IMAttrList object currently used by text.
 *        It should be released by caller.
 */
IMAttrList*     im_text_dup_attr_list           (const IMText       *text);

/**
 * @brief Compare two IMText objects.
 *
 * Only text content will be compared.
 *
 * @param text1 a pointer to an IMText object
 * @param text2 a pointer to another IMText object
 *
 * @return This function compares the two strings text1 and text2.  It returns
 *        an integer less than, equal to, or greater than zero if  text1  is  found,
 *        respectively, to be less than, to match, or be greater than text2.
 */
IMInt           im_text_compare                 (const IMText       *text1,
                                                 const IMText       *text2);
/**
 * @brief Compare two IMText objects for a specified length.
 *
 * Only a specified length of text content will be compared.
 *
 * @param text1 a pointer to an IMText object
 * @param text2 a pointer to another IMText object
 * @param len the lenght of text1 and text2. If the number characters of text1 and text2 are longer than
 *          len, more characrers will be ignored.
 *
 * @return This function compares the two strings text1 and text2.  It returns
 *        an integer less than, equal to, or greater than zero if  text1  is  found,
 *        respectively, to be less than, to match, or be greater than text2.
 */
IMInt           im_text_n_compare               (const IMText       *text1,
                                                 const IMText       *text2,
                                                 IMSize              len);
/**
 * @brief Prepend arbitrary UTF-8 encoded printf result
 *        to a specified text.
 *
 * @param text a IMText object.
 * @param format format string.
 * @param ... arbitrary variables to be printed according to format string.
 * @return text
 */
IMText*         im_text_prepend_utf8_printf     (IMText             *text,
                                                 const IMChar       *format,
                                                 ...) IM_GNUC_PRINTF(2,3);

/**
 * @brief Append arbitrary UTF-8 encoded printf result
 *        to a specified text.
 *
 * @param text a IMText object.
 * @param format format string.
 * @param ... arbitrary variables to be printed according to format string.
 * @return text
 */
IMText*         im_text_append_utf8_printf      (IMText             *text,
                                                 const IMChar       *format,
                                                 ...) IM_GNUC_PRINTF(2,3);

/**
 * @brief Insert arbitrary UTF-8 encoded printf result
 *        to a specified text at specified position.
 *
 * @param text a IMText object.
 * @param format format string.
 * @param ... arbitrary variables to be printed according to format string.
 * @return text
 */
IMText*         im_text_insert_utf8_printf      (IMText             *text,
                                                 IMSize              pos,
                                                 const IMChar       *format,
                                                 ...) IM_GNUC_PRINTF(3,4);

IM_END_DECLS
/** @} */

#endif
/*
vi:ts=4:nowrap:ai:expandtab
*/
